//! 标准库错误处理示例
//!
//! 演示如何实现 std::error::Error trait 来定义自定义错误类型
//!
//! ## 知识点总结
//!
//! | 错误类型 | 实现要点 | 使用场景 |
//! |---------|---------|---------|
//! | 基本错误类型 | 实现 Display 和 Error trait | 简单错误信息 |
//! | 带来源的错误 | 实现 source() 方法 | 错误链处理 |
//! | 带上下文的错误 | 包含额外错误信息 | 提供更详细的错误上下文 |
//! | 枚举错误类型 | 为每个变体实现处理逻辑 | 多种可能错误的统一处理 |
//!
//! ## 错误处理最佳实践
//!
//! 1. 为自定义错误类型实现 std::error::Error trait
//! 2. 实现 Display trait 提供用户友好的错误信息
//! 3. 实现 source() 方法支持错误链
//! 4. 使用 From trait 简化错误转换
//! 5. 合理使用错误枚举统一处理多种错误类型

use std::error::Error;
use std::fmt;

/// 1. 基本自定义错误类型
///
/// 实现最简单的自定义错误类型
#[derive(Debug)]
pub struct BasicError {
    details: String,
}

impl BasicError {
    pub fn new(msg: &str) -> BasicError {
        BasicError { details: msg.to_string() }
    }
}

impl fmt::Display for BasicError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for BasicError {}

/// 2. 带来源错误的自定义错误类型
///
/// 实现支持错误链的自定义错误类型
#[derive(Debug)]
pub struct ChainError {
    details: String,
    source: Option<Box<dyn Error>>,
}

impl ChainError {
    pub fn new(msg: &str) -> Self {
        ChainError { details: msg.to_string(), source: None }
    }

    pub fn with_source(msg: &str, source: Box<dyn Error>) -> Self {
        ChainError { details: msg.to_string(), source: Some(source) }
    }
}

impl fmt::Display for ChainError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for ChainError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.source.as_ref().map(|e| e.as_ref())
    }
}

/// 3. 带上下文信息的错误类型
///
/// 错误类型包含额外的上下文信息
#[derive(Debug)]
pub struct ContextError {
    operation: String,
    resource: String,
    source: Option<Box<dyn Error>>,
}

impl ContextError {
    pub fn new(operation: &str, resource: &str) -> Self {
        ContextError {
            operation: operation.to_string(),
            resource: resource.to_string(),
            source: None,
        }
    }

    pub fn with_source(operation: &str, resource: &str, source: Box<dyn Error>) -> Self {
        ContextError {
            operation: operation.to_string(),
            resource: resource.to_string(),
            source: Some(source),
        }
    }
}

impl fmt::Display for ContextError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(source) = &self.source {
            write!(f, "无法在 {} 上执行 {}: {}", self.resource, self.operation, source)
        } else {
            write!(f, "无法在 {} 上执行 {}", self.resource, self.operation)
        }
    }
}

impl Error for ContextError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.source.as_ref().map(|e| e.as_ref())
    }
}

/// 4. 枚举形式的错误类型
///
/// 使用枚举统一处理多种错误类型
#[derive(Debug)]
pub enum DatabaseError {
    ConnectionError(String),
    QueryError(String),
    IoError(std::io::Error),
}

impl fmt::Display for DatabaseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DatabaseError::ConnectionError(msg) => write!(f, "连接错误: {}", msg),
            DatabaseError::QueryError(msg) => write!(f, "查询错误: {}", msg),
            DatabaseError::IoError(err) => write!(f, "IO 错误: {}", err),
        }
    }
}

impl Error for DatabaseError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            DatabaseError::ConnectionError(_) => None,
            DatabaseError::QueryError(_) => None,
            DatabaseError::IoError(err) => Some(err),
        }
    }
}

// 为标准库错误实现转换
impl From<std::io::Error> for DatabaseError {
    fn from(error: std::io::Error) -> Self {
        DatabaseError::IoError(error)
    }
}

/// 演示基本错误类型
pub fn basic_error_example() -> Result<(), BasicError> {
    Err(BasicError::new("这是一个基本错误"))
}

/// 演示带来源的错误类型
pub fn chain_error_example() -> Result<(), ChainError> {
    // 模拟一个来源错误
    let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "文件未找到");
    let boxed_error: Box<dyn Error> = Box::new(io_error);

    Err(ChainError::with_source("读取配置失败", boxed_error))
}

/// 演示带上下文的错误类型
pub fn context_error_example() -> Result<(), ContextError> {
    let io_error = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "权限被拒绝");
    let boxed_error: Box<dyn Error> = Box::new(io_error);

    Err(ContextError::with_source("读取", "config.txt", boxed_error))
}

/// 演示枚举错误类型
pub fn enum_error_example() -> Result<(), DatabaseError> {
    // 模拟 IO 错误
    let io_error = std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "连接被拒绝");
    Err(DatabaseError::IoError(io_error))
}

/// 演示错误链处理
pub fn error_chain_example() {
    println!("=== 错误链示例 ===");

    // 基本错误
    match basic_error_example() {
        Ok(()) => println!("操作成功"),
        Err(e) => {
            println!("错误: {}", e);
            if let Some(source) = e.source() {
                println!("来源: {}", source);
            }
        },
    }

    // 带来源的错误
    match chain_error_example() {
        Ok(()) => println!("操作成功"),
        Err(e) => {
            println!("错误: {}", e);
            if let Some(source) = e.source() {
                println!("来源: {}", source);
            }
        },
    }

    // 带上下文的错误
    match context_error_example() {
        Ok(()) => println!("操作成功"),
        Err(e) => {
            println!("错误: {}", e);
            if let Some(source) = e.source() {
                println!("来源: {}", source);
            }
        },
    }

    // 枚举错误
    match enum_error_example() {
        Ok(()) => println!("操作成功"),
        Err(e) => {
            println!("错误: {}", e);
            if let Some(source) = e.source() {
                println!("来源: {}", source);
            }
        },
    }
}

/// 主演示函数
pub fn demonstrate_std_errors() {
    println!("=== 标准库错误处理示例 ===");

    error_chain_example();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_error() {
        let error = BasicError::new("测试错误");
        assert_eq!(error.to_string(), "测试错误");
        assert!(error.source().is_none());
    }

    #[test]
    fn test_chain_error() {
        let error = ChainError::new("链式错误");
        assert_eq!(error.to_string(), "链式错误");
        assert!(error.source().is_none());

        let io_error = std::io::Error::new(std::io::ErrorKind::Other, "IO错误");
        let boxed_error: Box<dyn Error> = Box::new(io_error);
        let error_with_source = ChainError::with_source("带来源的错误", boxed_error);
        assert!(error_with_source.source().is_some());
    }

    #[test]
    fn test_context_error() {
        let error = ContextError::new("读取", "文件.txt");
        assert!(error.source().is_none());
        assert!(error.to_string().contains("读取"));
        assert!(error.to_string().contains("文件.txt"));
    }

    #[test]
    fn test_database_error() {
        let conn_error = DatabaseError::ConnectionError("连接超时".to_string());
        assert!(conn_error.source().is_none());

        let io_error = std::io::Error::new(std::io::ErrorKind::Other, "IO错误");
        let db_error = DatabaseError::IoError(io_error);
        assert!(db_error.source().is_some());
    }

    #[test]
    fn test_error_examples() {
        assert!(basic_error_example().is_err());
        assert!(chain_error_example().is_err());
        assert!(context_error_example().is_err());
        assert!(enum_error_example().is_err());
    }
}
